#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include <malloc.h>

#include "ennemi.h"


ennemi* ennemiInit(terrain* ter, const int cooX, const int cooY)
{
    int i=0;
    ennemi* vilain = malloc(3*sizeof(int)+sizeof(clock_t));
    ennemiSetX(vilain, cooX);
    ennemiSetY(vilain, cooY);

    while (ter->ennemiTab[i] != 0)
        i++;
    ennemiSetNumero(vilain, i);
    ter->ennemiTab[i] = vilain;
    ter->ennemiTab[i]->heureInit = clock();
    ennemiAffiche(vilain,ter);
    return vilain;
}

void ennemiDetruire(ennemi* vilain, terrain* ter)
{
    if(vilain != 0)
    {
        free(vilain);
        ter->ennemiTab[vilain->num] = 0;
    }
}

void ennemiSetNumero(ennemi* vilain, const int i)
{
    vilain->num = i;
}

void ennemiSetX(ennemi* vilain, const int abs)
{
    vilain->x = abs;
}

void ennemiSetY(ennemi* vilain, const int ord)
{
    vilain->y = ord;
}

int ennemiGetX(const ennemi* vilain)
{
    return vilain->x;
}

int ennemiGetY(const ennemi* vilain)
{
    return vilain->y;
}

int ennemiGetNum(const ennemi* vilain)
{
    return vilain->num;
}

void ennemiGauche(ennemi* vilain, terrain* ter)
{
    int y,x;
    x=ennemiGetX(vilain);
    y=ennemiGetY(vilain);
    if (terrainPositionValide(ter, x-1, y))
    {
        ennemiSetX(vilain,x - 1);
        terrainSetXY(ter, x, y, '.');
    }

}

void ennemiDroite(ennemi* vilain, terrain* ter)
{
    int y,x;
    x=ennemiGetX(vilain);
    y=ennemiGetY(vilain);
    if (terrainPositionValide(ter, x+1, y))
    {
        ennemiSetX(vilain, x + 1);
        terrainSetXY(ter, x, y, '.');
    }

}

void ennemiBas(ennemi* vilain, terrain* ter)
{
    int y,x;
    x=ennemiGetX(vilain);
    y=ennemiGetY(vilain);
    if (terrainPositionValide(ter, x, y+1))
    {
        ennemiSetY(vilain, y + 1);
        terrainSetXY(ter, x, y, '.');
    }

}

void ennemiHaut(ennemi* vilain,  terrain* ter)
{
    int y,x;
    x=ennemiGetX(vilain);
    y=ennemiGetY(vilain);
	assert(vilain);
	assert(ter);
    if (terrainPositionValide(ter, x, y-1))
    {
        ennemiSetY(vilain, y - 1);
        terrainSetXY(ter, x, y, '.');
    }
}

void ennemiAffiche(const ennemi* vilain, terrain* ter)
{
    terrainSetXY(ter, ennemiGetX(vilain), ennemiGetY(vilain), ennemiGetNum(vilain) + '0');
}

int nombre_aleatoire(const int a, const int b) /* retourne un nombre aleatoire entre a et b (b non inclus) */
/* a < b */
{
    return rand()%(b-a) + a;
}

void ennemiDeplaceAleatoirement(ennemi* vilain, terrain* ter)
{
    int n = nombre_aleatoire(1,5);
    clock_t temps = clock();
    assert(n>=1 && n<=4);
    assert(temps > 0);
    /* un ennemi prend 0.5 seconde entre chacun de ses déplacements */
    if (temps - vilain->heureInit >= 500000)
    {
        switch (n)
        {
          case 1:
              ennemiGauche(vilain,ter);
              break;
          case 2:
              ennemiDroite(vilain,ter);
              break;
          case 3:
              ennemiHaut(vilain,ter);
              break;
          case 4:
              ennemiBas(vilain,ter);
              break;
        }
        vilain->heureInit = clock();
    }
}

char rechercheObjectifAttaque(const ennemi* vilain, terrain* ter, int x, int y) /* x et y sont les positions de mario */
{
    char c = 'n';
    int a,b;
    assert(x>0 && x< getTailleX(ter));
    assert(y>0 && y< getTailleY(ter));

    a = ennemiGetX(vilain);
    b = ennemiGetY(vilain);

    initNumCheminTab(ter->numCheminTab, getTailleX(ter), getTailleY(ter));
    remplirNumCheminTab(ter->terrainTab, ter->numCheminTab, b,a, 0, 'x', 1);

    c = ter->numCheminTab[x][y].deplacement;
    while(ter->numCheminTab[x][y].deplacement != 'x')
    {
            c = ter->numCheminTab[x][y].deplacement;
            if(c =='n') return c;

            assert(c =='B' || c =='H' ||c =='G' ||c =='D');


            if(ter->numCheminTab[x][y].deplacement == 'D')
                y--;
            else if(ter->numCheminTab[x][y].deplacement == 'G')
                y++;
            else if(ter->numCheminTab[x][y].deplacement == 'B')
                x--;
            else if(ter->numCheminTab[x][y].deplacement == 'H')
                x++;
    }

    return c;
}

char rechercheObjectifDefense(const ennemi* vilain, terrain* ter)
{

    char c = 'n';
    int a,b;
    int* x = (int*)malloc(sizeof(int));
    int* y = (int*)malloc(sizeof(int));

    a = ennemiGetX(vilain);
    b = ennemiGetY(vilain);
    *x = *y = 0;

    initNumCheminTab(ter->numCheminTab, getTailleX(ter), getTailleY(ter));
    remplirNumCheminTab(ter->terrainTab, ter->numCheminTab, b,a, 0, 'x', 0);
    caseSansDanger(ter,x,y);

    a = *x;
    b = *y;
    c = ter->numCheminTab[a][b].deplacement;
    free(x);
    free(y);


    while(ter->numCheminTab[a][b].deplacement != 'x')
    {
            c = ter->numCheminTab[a][b].deplacement;
            if(c =='n') return c;

            assert(c =='B' || c =='H' ||c =='G' ||c =='D');

            if(ter->numCheminTab[a][b].deplacement == 'D')
                b--;
            else if(ter->numCheminTab[a][b].deplacement == 'G')
                b++;
            else if(ter->numCheminTab[a][b].deplacement == 'B')
                a--;
            else if(ter->numCheminTab[a][b].deplacement == 'H')
                a++;
    }
    return c;
}

void caseSansDanger(terrain* ter, int* x, int* y)
{
        int i = 0;
        int j = 0;
        int n = 1000;

        for(i=1;i<14;i++)
        {
            for(j=1;j<14 ;j++)
            {
                if(ter->terrainTab[i][j] != '#' && ter->dangerTab[i][j] == 0 && ter->numCheminTab[i][j].num < n)
                {
                    n = ter->numCheminTab[i][j].num;
                    *x = i;
                    *y = j;
                }
            }
        }
}


void ennemiDeplaceIA(ennemi* vilain, terrain* ter, const int x, const int y) /* x et y sont les positions de Mario */
{
    char c;
    int danger = 0;
    clock_t temps = clock();

    assert(x>0 && x< getTailleX(ter));
    assert(y>0 && y< getTailleY(ter));
    assert(temps >= 0);
    remplirDangerTab(ter,1);

    danger = estZoneDanger(ter->dangerTab, ennemiGetX(vilain), ennemiGetY(vilain));

    if (danger == 0)
    {
        c = rechercheObjectifAttaque(vilain, ter, y, x );
    }
    else
    {
        c = rechercheObjectifDefense(vilain, ter);
    }

    /* un ennemi prend 0.5 seconde entre chacun de ses déplacements */

    if (c != 'n' && c != 'x')
    {
        assert(c =='B' || c =='H' ||c =='G' ||c =='D');
        if (temps - vilain->heureInit >= 500000)
        {
            if(danger == 0)
            {
                    switch (c) /* on verifie si la case suivante n'est pas dangereuse, si non on se déplace. */
                                /* si la case suivante est une caisse, l'ennemi a 1/2 chance de poser une bombe */
                    {
                      case 'G':
                         if(estZoneDanger(ter->dangerTab, ennemiGetX(vilain)-1, ennemiGetY(vilain)) != 1)
                         {
                             if(ter->terrainTab[ennemiGetY(vilain)][ennemiGetX(vilain)-1] == 'C')
                             {
                                 ennemiPoseBombe(vilain,ter,3);
                             }
                             else ennemiGauche(vilain,ter);
                         }

                          break;
                      case 'D':
                          if(estZoneDanger(ter->dangerTab, ennemiGetX(vilain)+1, ennemiGetY(vilain)) != 1)
                          {
                             if(ter->terrainTab[ennemiGetY(vilain)][ennemiGetX(vilain)+1] == 'C')
                             {
                                 ennemiPoseBombe(vilain,ter,3);
                             }
                             else ennemiDroite(vilain,ter);
                          }
                          break;
                      case 'H':
                          if(estZoneDanger(ter->dangerTab, ennemiGetX(vilain), ennemiGetY(vilain)-1) != 1)
                          {
                             if(ter->terrainTab[ennemiGetY(vilain)-1][ennemiGetX(vilain)] == 'C')
                             {
                                 ennemiPoseBombe(vilain,ter,3);
                             }
                             else ennemiHaut(vilain,ter);
                          }
                          break;
                      case 'B':
                          if(estZoneDanger(ter->dangerTab, ennemiGetX(vilain), ennemiGetY(vilain)+1) != 1)
                          {
                             if(ter->terrainTab[ennemiGetY(vilain)+1][ennemiGetX(vilain)] == 'C')
                             {
                                 ennemiPoseBombe(vilain,ter,3);
                             }
                             else ennemiBas(vilain,ter);
                          }
                          break;
                    }
            }
            else {
                      switch (c)
                      {
                        case 'G':
                            ennemiGauche(vilain,ter);
                            break;
                        case 'D':
                            ennemiDroite(vilain,ter);
                            break;
                        case 'H':
                            ennemiHaut(vilain,ter);
                            break;
                        case 'B':
                            ennemiBas(vilain,ter);
                            break;
                      }
                }
           vilain->heureInit = clock();
        }
    }
}


void ennemiPoseBombe(const ennemi* vilain, terrain* ter, const int nb)
{
        int n = nombre_aleatoire(1, nb);
        assert(vilain);
        assert(ter);
        assert(n>=0);
        assert(n<nb);
        if(n == 1)
        {
            bombe* bombe = bombeInit(ter, ennemiGetX(vilain), ennemiGetY(vilain), 0, 0);
            bombeAffiche(bombe, ter);
        }
}
